﻿using LJ.EventBus.Abstractions;
using LJ.EventBus.FastDog.Data;
using LJ.EventBus.FastDog.Transport.Abstractions;
using LJ.FaultHandler.Abstractions;
using LJ.IdGenerator.Abstractions;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;

namespace LJ.EventBus.FastDog.Internal;

public class EventBusPublisher(IPackBootstrapper packBootstrapper, IIdGenerator idGenerator, IFaultHandlerFactory faultHandlerFactory, IMessageSerializer messageSerializer, ITransport messageSender) : IEventBusPublisher
{
    private readonly IPackBootstrapper _packBootstrapper = packBootstrapper;
    private readonly IIdGenerator _idGenerator = idGenerator;
    private readonly IFaultHandlerFactory _faultHandlerFactory = faultHandlerFactory;
    private readonly IMessageSerializer _messageSerializer = messageSerializer;
    private readonly ITransport _messageSender = messageSender;

    public async Task PublishAsync<T>(string name, T value, CancellationToken cancellationToken = default)
    {
        var headers = new Dictionary<string, string?>
        {
        };
        await PublishInternalAsync(name, value, headers, cancellationToken);
    }

    public async Task PublishAsync<T>(string name, T value, IDictionary<string, string?> headers , CancellationToken cancellationToken = default)
    {
        await PublishInternalAsync(name, value, headers, cancellationToken);
    }

    private async Task PublishInternalAsync<T>(string name, T value, IDictionary<string, string?> headers,CancellationToken cancellationToken = default)
    {
        ArgumentNullException.ThrowIfNull(value, nameof(value));

        if (!_packBootstrapper.IsStarted)
        {
            throw new InvalidOperationException("EventBus has not been started!");
        }

        if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));


        if (!headers.ContainsKey(MessageHeaders.MessageId))
        {
            var messageId = _idGenerator.Create().ToString();
            headers.Add(MessageHeaders.MessageId, messageId);
        }

        headers.Add(MessageHeaders.MessageName, name);

        var publishTime = DateTime.Now;

        headers.Add(MessageHeaders.SentTime, publishTime.ToString(CultureInfo.InvariantCulture));

        var message = new Message(headers, value);

        var transportMsg =  _messageSerializer.Serialize(message);

        var faultHandler = _faultHandlerFactory.Create();

        await faultHandler.ExecuteAsync(async a => {

           await _messageSender.SendAsync(transportMsg,a);
           
        }, cancellationToken);


    }

}
